import java.util.Comparator;
import java.util.Objects;
import java.util.PriorityQueue;

//Alt+R  修改多个变量
//        Ctrl+Alt+←  或者  → 可以查看源码的上一层或者下一层
class Card implements Comparable<Card>{//比较接口  自定义类型比较需要加上比较接口
    public int rank; // 数值
    public String suit; // 花色
    public Card(int rank, String suit) {
        this.rank = rank; this.suit = suit;
    }

    @Override
    public int compareTo(Card o) {//比较方式
        return this.rank - o.rank;//小根堆
//        return o.rank - this.rank//大根堆
//        这种写法对类的侵入性太强了。一旦写好了 就根据那种规则比较 那么就不能轻易进行修改了。
//        所以我们使用另一种方式  自己写比较器方法类
    }

    @Override
    public String toString() {
        return "Card{" +
                "rank=" + rank +
                ", suit='" + suit + '\'' +
                '}';
    }




//    equal比较方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
//        //getClass() != o.getClass()比较是不是同一个类名
        if (o == null || getClass() != o.getClass()) return false;
        Card card = (Card) o;
        return rank == card.rank && Objects.equals(suit, card.suit);
    }

    @Override
    public int hashCode() {
        return Objects.hash(rank, suit);
    }//先不关心
}








//      比较器类方法  大堆和小堆
class BigRankComparator implements Comparator<Card> {
    public int compare(Card o1, Card o2) {
        return o2.rank - o1.rank;
    }
}
class SmallRankComparator implements Comparator<Card> {
    public int compare(Card o1, Card o2) {
        return o1.rank - o2.rank;
    }
}








public class TestDemo {
    public static void main1(String[] args) {
        TestHeap testHeap = new TestHeap();
        int[] array = {27,15,19,18,28,34,65,49,25,37};
        testHeap.createBigHeap(array);
//        elem = [65 49 34 25 37 27 19 18 15 28]
        System.out.println("===============");//在这打个断点
    }

    public static void main2(String[] args) {
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
//        没放一个元素都保证当前元素是大堆 或者是 小堆
//        每次入队的时候，都得保证当前是大堆或者小堆


        priorityQueue.offer(12);
        priorityQueue.offer(4);
        priorityQueue.offer(15);
        System.out.println(priorityQueue.peek());//4   是小堆

        System.out.println(priorityQueue.poll());//4    保证每次弹出一个元素之后，仍然是小根堆或者大根堆
        System.out.println(priorityQueue.poll());//12   每次弹出去都是最小的元素
    }


    public static void main3(String[] args) {
        TestHeap testHeap = new TestHeap();
        int[] array = {27,15,19,18,28,34,65,49,25,37};
        testHeap.createBigHeap(array);
//        elem = [65 49 34 25 37 27 19 18 15 28]
        System.out.println("===============");
        testHeap.offer(80);
//        elem = [80, 65, 34, 25, 49, 27, 19, 18, 15, 28, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        System.out.println("===============");
        System.out.println(testHeap.poll());//80
        System.out.println(testHeap.peek());//65
    }


    public static void main4(String[] args) {
        TestHeap testHeap = new TestHeap();
        int[] array = {27,15,19,18,28,34,65,49,25,37};
        testHeap.createBigHeap(array);
        testHeap.heapSort();//elem = [15, 18, 19, 25, 27, 28, 34, 37, 49, 65]
        System.out.println("==========");
    }



//    优先级队列在插入元素时有个要求：插入的元素不能是null或者元素之间必须要能够进行比较，
    public static void main5(String[] args) {
        PriorityQueue<Card> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(new Card(2,"♥"));//直接放到底层的queue的0下标中
//        priorityQueue.offer(null);//error
        priorityQueue.offer(new Card(1,"♥"));//在offer()中 因为i!=0 所以会进行siftUp
//        Ctrl+Alt+←  或者  → 可以查看源码的上一层或者下一层
        System.out.println(priorityQueue);//结果  [Card{rank=1, suit='♥'}, Card{rank=2, suit='♥'}] 小根堆
//        发现我们并没有调用compareTo()  它自动帮我们排序了   关键在于offer()方法
        Card card3 = new Card(4,"♦");
        priorityQueue.offer(card3);
        System.out.println(priorityQueue);//[Card{rank=1, suit='♥'}, Card{rank=2, suit='♥'}, Card{rank=4, suit='♦'}]

        Card card4 = new Card(3,"♠");
        System.out.println(card3.compareTo(card4));//1
        System.out.println(card4.compareTo(card3));//-1
        System.out.println(card3.compareTo(card3));//0
    }



//  比较器的比较方法
    public static void main6(String[] args) {
        Card card1 = new Card(1,"♠");
        Card card2 = new Card(2,"♦");

        BigRankComparator BigRankComparator = new BigRankComparator();
        int ret = BigRankComparator.compare(card1,card2);
        System.out.println(ret);//-1
    }


//  自己传入比较器
//
//    大根堆
//    1.
    public static void main7(String[] args) {
        Card card1 = new Card(2,"♠");
        Card card2 = new Card(1,"♦");
        Card card3 = new Card(5,"♦");
        BigRankComparator BigRankComparator = new BigRankComparator();
        PriorityQueue<Card> priorityQueue = new PriorityQueue<>(BigRankComparator);
        priorityQueue.offer(card1);
        priorityQueue.offer(card2);
        priorityQueue.offer(card3);
        System.out.println(priorityQueue);
        // [Card{rank=5, suit='♦'}, Card{rank=1, suit='♦'}, Card{rank=2, suit='♠'}]
    }
//      2.小根堆
    public static void main8(String[] args) {
        Card card1 = new Card(2,"♠");
        Card card2 = new Card(1,"♦");
        Card card3 = new Card(5,"♦");
        SmallRankComparator smallRankComparator = new SmallRankComparator();
        PriorityQueue<Card> priorityQueue = new PriorityQueue<>(smallRankComparator);
        priorityQueue.offer(card1);
        priorityQueue.offer(card2);
        priorityQueue.offer(card3);
        System.out.println(priorityQueue);
        // [Card{rank=1, suit='♦'}, Card{rank=2, suit='♠'}, Card{rank=5, suit='♦'}]
    }


//    3.更加简便 这里不是new一个（实例化）接口  我们将该接口放到括号内部  称为匿名内部类
    public static void main9(String[] args) {
        Card card1 = new Card(2,"♠");
        Card card2 = new Card(1,"♦");
        Card card3 = new Card(5,"♦");


        PriorityQueue<Card> priorityQueue = new PriorityQueue<>(
                new Comparator<Card>() {
                    @Override
                    public int compare(Card o1, Card o2) {
                        return o2.rank - o1.rank;//大堆
                    }
                }
        );
//        这样写也是一样的
        PriorityQueue<Card> priorityQueue2 = new PriorityQueue<>((x,y)->{return y.rank-x.rank;});
//          (x,y)->{return y.rank-x.rank;} 被称为lambda表达式   可读性非常差


        priorityQueue.offer(card1);
        priorityQueue.offer(card2);
        priorityQueue.offer(card3);
        System.out.println(priorityQueue);
//        [Card{rank=5, suit='♦'}, Card{rank=1, suit='♦'}, Card{rank=2, suit='♠'}]
    }






//    equal方法
    public static void main(String[] args) {
        Card card1 = new Card(2,"♠");
        Card card2 = new Card(5,"♦");
        Card card3 = new Card(5,"♦");
        System.out.println(card2.equals(card3));//false  没重写equal方法之前 查看源码 发现比较的是object地址
//        在 Card 中重写equal方法 结果为true
    }
}
